// Optimize layout by avoiding an extra EXACTLY pass when the view is // already measured as the correct size. In API 23 and below, this // extra pass is required to make LinearLayout re-distribute weight. finalbooleanspecChanged= widthMeasureSpec != mOldWidthMeasureSpec || heightMeasureSpec != mOldHeightMeasureSpec; finalbooleanisSpecExactly= MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; finalbooleanmatchesSpecSize= getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); finalbooleanneedsLayout= specChanged && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
if (forceLayout || needsLayout) { // first clears the measured dimension flag mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
resolveRtlPropertiesIfNeeded();
intcacheIndex= forceLayout ? -1 : mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { // measure ourselves, this should set the measured dimension flag back onMeasure(widthMeasureSpec, heightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } else { longvalue= mMeasureCache.valueAt(cacheIndex); // Casting a long to int drops the high 32 bits, no mask needed setMeasuredDimensionRaw((int) (value >> 32), (int) value); mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; }
// flag not set, setMeasuredDimension() was not invoked, we raise // an exception to warn the developer if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { thrownewIllegalStateException("View with id " + getId() + ": " + getClass().getName() + "#onMeasure() did not set the" + " measured dimension by calling" + " setMeasuredDimension()"); }
/** * Measure specification mode: The parent has not imposed any constraint * on the child. It can be whatever size it wants. */ publicstaticfinalintUNSPECIFIED=0 << MODE_SHIFT;
/** * Measure specification mode: The parent has determined an exact size * for the child. The child is going to be given those bounds regardless * of how big it wants to be. */ publicstaticfinalintEXACTLY=1 << MODE_SHIFT;
/** * Measure specification mode: The child can be as large as it wants up * to the specified size. */ publicstaticfinalintAT_MOST=2 << MODE_SHIFT; }
@Override protectedvoidonLayout(boolean changed, int left, int top, int right, int bottom) { layoutChildren(left, top, right, bottom, false/* no force left gravity */); }
voidlayoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) { finalintcount= getChildCount();
finalintparentLeft= getPaddingLeftWithForeground(); finalintparentRight= right - left - getPaddingRightWithForeground();
finalintparentTop= getPaddingTopWithForeground(); finalintparentBottom= bottom - top - getPaddingBottomWithForeground();
for (inti=0; i < count; i++) { finalViewchild= getChildAt(i); if (child.getVisibility() != GONE) { finalLayoutParamslp= (LayoutParams) child.getLayoutParams();
publicvoiddraw(Canvas canvas) { /* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) * 7. If necessary, draw the default focus highlight */
drawBackground(canvas);
saveCount = canvas.getSaveCount();
// Step 3, draw the content onDraw(canvas);
// Step 4, draw the children dispatchDraw(canvas);
// Step 5, draw the fade effect and restore layers // canvas.drawXXX canvas.restoreToCount(saveCount);
// Step 7, draw the default focus highlight drawDefaultFocusHighlight(canvas); }
分为7步
绘制背景
获取当前画布save次数,记录状态
绘制内容,由onDraw实现
绘制子view
恢复步骤2的画布状态
绘制前景,滚动条
如果获取了焦点,绘制一个高光
1 2 3 4 5 6 7
/** * Implement this to do your drawing. * * @param canvas the canvas on which the background will be drawn */ protectedvoidonDraw(Canvas canvas) { }
1 2 3 4 5 6 7 8 9
/** * Called by draw to draw the child views. This may be overridden * by derived classes to gain control just before its children are drawn * (but after its own view has been drawn). * @param canvas the canvas on which to draw the view */ protectedvoiddispatchDraw(Canvas canvas) {
}
ViewGroup的dispatchDraw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@Override protectedvoiddispatchDraw(Canvas canvas) { // ... for (inti=0; i < childrenCount; i++) { // ...